home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume9 / elm2 / part04 < prev    next >
Encoding:
Internet Message Format  |  1987-03-08  |  56.3 KB

  1. Subject:  v09i004:  ELM Mail System, Part04/19
  2. Newsgroups: mod.sources
  3. Approved: rs@mirror.TMC.COM
  4.  
  5. Submitted by: Dave Taylor <hplabs!taylor>
  6. Mod.sources: Volume 9, Issue 4
  7. Archive-name: elm2/Part04
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line,
  11. # then unpack it by saving it in a file and typing "sh file".
  12. # If this archive is complete, you will see the message:
  13. #        "End of archive 4 (of 19)."
  14. # Contents:  Overview filter/filter.c filter/utils2.c src/aliaslib.c
  15. #   src/edit.c src/file_utils.c src/mailtime.c src/opt_utils.c
  16. #   src/sort.c src/syscall.c
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. echo shar: Extracting \"Overview\" \(5333 characters\)
  19. if test -f Overview ; then 
  20.   echo shar: Will not over-write existing file \"Overview\"
  21. else
  22. sed "s/^X//" >Overview <<'END_OF_Overview'
  23. X            An Overview of the Elm Mail System
  24. X            ----------------------------------
  25. X
  26. XIntroduction
  27. X
  28. X    This file discusses the functionality of the Elm mail system
  29. Xand explains some of the motivation behind the creation and of various
  30. Xfeatures.
  31. X
  32. X1. What is Elm?
  33. X
  34. X    Currently on Unix, there seems to be a preponderence of line-oriented 
  35. Xsoftware.  This is most unfortunate as most of the software on Unix tends to
  36. Xbe pretty darn hard to use!  I believe that there is more than a slight
  37. Xcorrelation between the two, and, since I was myself having problems using
  38. X"mailx" with high-volume mail, I created a new mail system.
  39. X
  40. X    In the lingo of the mail guru, Elm is a "User Agent" system,  it's
  41. Xdesigned to run with "sendmail" or "/bin/rmail" (according to what's on
  42. Xyour system) and is a full replacement of programs like "/bin/mail" and
  43. X"mailx".  The system is more than just a single program, however, and
  44. Xincludes programs like "from" to list a 'table of contents' of your
  45. Xmail, "printmail" to quickly paginate mail files (to allow 'clean'
  46. Xprintouts), and "autoreply", a systemwide daemon that can autoanswer
  47. Xmail for people while they're on vacation without having multiple
  48. Xcopies spawned on the system.
  49. X
  50. X2. What's New about Elm?
  51. X
  52. X    The most significant difference between Elm and earlier mail
  53. Xsystems is that Elm is screen-oriented.  Upon further use, however,
  54. Xusers will find that Elm is also quite a bit easier to use, and quite
  55. Xa bit more "intelligent" about sending mail and so on.   For example,
  56. Xsay you're on "usenet" and receive a message from someone on the
  57. XARPANET.  The sender also "cc'd" another person on ARPA.  With Elm
  58. Xyou can simply G)roup reply and it will build the correct return
  59. Xaddresses.
  60. X
  61. X    There are lots of subtleties like that in the program, most of
  62. Xwhich you'll probably find when you need them.
  63. X
  64. X3. What systems does it work on?
  65. X
  66. X    Elm was originally written on HP-UX, HP's proprietary version
  67. Xof Bell system V, with a little BSD thrown in.  Since then, it has been
  68. Xported to Bell, Berkeley, Sun, UTS and the Pyramid and should run on 
  69. Xall these systems without any modifications (if there turn out to be 
  70. Xmodifications, please notify the author as soon as possible).
  71. X
  72. X    Some people have expressed interest in porting the mail system
  73. Xto Xenix.  If it is indeed 100% system V compatible it should be rather
  74. Xtrivial...
  75. X
  76. X4. Does it obey existing mail standards?
  77. X
  78. X    Yes!  That's another of the basic reasons the program was 
  79. Xoriginally written!  To ensure that the date field, the "From:" line
  80. Xand so on were all added in the correct format.  The program is 100%
  81. Xcorrect according to the RFC-822 electronic mail header protocol
  82. Xguide.
  83. X
  84. X5. What were the main motivating factors?
  85. X
  86. X    The first two I've already mentioned, but here's a (somewhat
  87. Xpartial) list;
  88. X
  89. X    -  To have a mail system that exploited the CRT instead of
  90. X       assuming I'm on a teletype.
  91. X
  92. X    - To have a mailer that was 100% correct when dealing with     
  93. X      network mail (ie RFC-822).
  94. X
  95. X    - To create a system that needed no documentation for the
  96. X      casual user, but was still powerful enough and sophisticated
  97. X      enough for a mail expert.
  98. X
  99. X    - To write a "significant" piece of software as a learning
  100. X      experience (I admit it!)
  101. X
  102. X    - To find out how reasonable it is to try to modify a program
  103. X      to meet the expectations of the users, rather than vice-versa.
  104. X
  105. X    - To basically correct some of the dumb things that the current
  106. X      mailers do, like letting you send mail to addresses that it
  107. X      could trivially figure out are going to result in 'dead.letter'
  108. X
  109. X    - To tie in intimately with the pathalias program output, and
  110. X      allow users to specify machine!user or user@machine and have
  111. X      the COMPUTER do the work of figuring out addresses...
  112. X
  113. X6. Is it reliable?
  114. X
  115. X    The mailer, in various incarnations, has logged literally
  116. Xthousands upon thousands of hours without any problems that aren't
  117. Xnow corrected.  As new problems arise they're dealt with in as
  118. Xrapid a manner as possible...
  119. X
  120. X7. What should I do now?
  121. X
  122. X    The first step would be to install the mail system and have
  123. Xthe "elm" mailbox/alias expand to my email address (hplabs!taylor).
  124. XThen, once it's all up and running, drop me a line letting me know
  125. Xthat your site is running the system (bookkeeping) and what you and
  126. Xyour site think of it.
  127. X
  128. X    REMEMBER: The product is evolving so if you'd like to have a
  129. Xsomething change, or have something new added, LET ME KNOW!!!  I'd 
  130. Xmuch rather make the change myself than start getting change reports
  131. Xmailed from around the world!!
  132. X
  133. X8. Disclaimers 
  134. X
  135. X    The author of this program will deny all liability for any
  136. Xdamages, either real or imagined, due to the execution of this program
  137. Xor anything related to either the software or the system.  Furthermore,
  138. Xthe entire system and all source within, including the presentation
  139. Xscreens and commands, are legally copyrighted by the author, and while
  140. Xthey can be used, and abused for public domain systems, will be in 
  141. Xviolation of the law if used in systems or programs sold for profit.
  142. X
  143. X    By installing the mailer or even extracting it from the network,
  144. Xyou are agreeing to the above disclaimer.
  145. X
  146. X9. Finally
  147. X
  148. X    I think it's a good program, and I can cite at least 75 people
  149. Xwho would (begrudgingly, I'm sure) agree.  You should most certainly
  150. Xinstall the program and try it!!
  151. X
  152. X
  153. X                -- Dave Taylor
  154. X                
  155. X                hplabs!taylor
  156. X
  157. XMarch 13th, 1986
  158. END_OF_Overview
  159. if test 5333 -ne `wc -c <Overview`; then
  160.     echo shar: \"Overview\" unpacked with wrong size!?
  161. fi
  162. # end of overwriting check
  163. fi
  164. echo shar: Extracting \"filter/filter.c\" \(5430 characters\)
  165. if test -f filter/filter.c ; then 
  166.   echo shar: Will not over-write existing file \"filter/filter.c\"
  167. else
  168. sed "s/^X//" >filter/filter.c <<'END_OF_filter/filter.c'
  169. X/**            filter.c            **/
  170. X
  171. X/** This program is used as a filter within the users ``.forward'' file
  172. X    and allows intelligent preprocessing of mail at the point between
  173. X    when it shows up on the machine and when it is actually put in the
  174. X    mailbox.
  175. X
  176. X    The program allows selection based on who the message is FROM, TO, or
  177. X    what the subject is.  Acceptable actions are for the program to DELETE
  178. X    the message, SAVE the message in a specified folder, FORWARD the message
  179. X    to a specified user, SAVE the message in a folder, but add a copy to the
  180. X    users mailbox anyway, or simply add the message to the incoming mail.
  181. X
  182. X    Filter also keeps a log of what it does as it goes along, and at the
  183. X    end of each `quantum' mails a summary of actions, if any, to the user.
  184. X
  185. X    Uses the files: $HOME/.filter for instructions to this program, and
  186. X    $HOME/.filterlog for a list of what has been done since last summary.
  187. X
  188. X   (C) Copyright 1986, Dave Taylor
  189. X**/
  190. X
  191. X
  192. X#include <stdio.h>
  193. X#include <pwd.h>
  194. X#include <ctype.h>
  195. X#ifdef BSD
  196. X# include <sys/time.h>
  197. X#else
  198. X# include <time.h>
  199. X#endif
  200. X#include <fcntl.h>
  201. X
  202. X#include "defs.h"
  203. X
  204. X#define  MAIN_ROUTINE            /* for the filter.h file, of course! */
  205. X#include "filter.h"
  206. X
  207. Xmain(argc, argv)
  208. Xint argc;
  209. Xchar *argv[];
  210. X{
  211. X    FILE   *fd;                /* for output to temp file! */
  212. X    struct passwd  *passwd_entry, 
  213. X               *getpwuid();        /* for /etc/passwd          */
  214. X    char filename[SLEN],            /* name of the temp file    */
  215. X         buffer[LONG_SLEN];            /* input buffer space       */
  216. X    int  in_header = TRUE,            /* for header parsing       */
  217. X         in_to     = FALSE,            /* are we on 'n' line To: ? */
  218. X         c;                    /* var for getopt routine   */
  219. X
  220. X    /* first off, let's get the info from /etc/passwd */ 
  221. X    
  222. X    if ((passwd_entry = getpwuid(getuid())) == NULL) 
  223. X      leave("Cannot get password entry for this uid!");
  224. X
  225. X    strcpy(home, passwd_entry->pw_dir);
  226. X    strcpy(username, passwd_entry->pw_name);
  227. X
  228. X    gethostname(hostname, sizeof(hostname));
  229. X
  230. X    /* now parse the starting arguments... */
  231. X
  232. X    while ((c = getopt(argc, argv, "aclnrSsv")) > 0) {
  233. X      switch (c) {
  234. X        case 'a' : audible = TRUE;                break;
  235. X        case 'c' : clear_logs = TRUE;            break;
  236. X        case 'l' : log_actions_only = TRUE;            break;
  237. X        case 'r' : if (get_filter_rules() == -1)
  238. X                 fprintf(stderr,"Couldn't get rules!\n");
  239. X               else
  240. X                 print_rules();
  241. X               exit(0);
  242. X        case 's' : if (get_filter_rules() == -1) exit(1);
  243. X                 show_summary();                 exit(0);
  244. X    
  245. X        case 'S' : long_summary = TRUE;    
  246. X                 show_summary();                 exit(0);
  247. X
  248. X        case 'n' : show_only = TRUE;            break;
  249. X        case 'v' : verbose = TRUE;                break;
  250. X      }
  251. X    }
  252. X
  253. X    if (c < 0) {
  254. X      fprintf(stderr, "Usage: | filter [-nrv]\n\   or: filter [-c] -s\n");
  255. X          exit(1);
  256. X    }
  257. X
  258. X    /* next, create the tempfile and save the incoming message */
  259. X
  260. X    sprintf(filename, "%s.%d", filter_temp, getpid());
  261. X
  262. X    if ((fd = fopen(filename,"w")) == NULL)
  263. X      leave("Cannot open temporary file!");
  264. X
  265. X    while (gets(buffer) != NULL) {
  266. X      if (in_header) {
  267. X
  268. X        if (! whitespace(buffer[0])) 
  269. X        in_to = FALSE;
  270. X
  271. X        if (the_same(buffer, "From ")) 
  272. X          save_from(buffer);
  273. X        else if (the_same(buffer, "Subject:")) 
  274. X          save_subject(buffer);
  275. X        else if (the_same(buffer, "To:")) {
  276. X          in_to++;
  277. X          save_to(buffer);
  278. X        }
  279. X        else if (the_same(buffer, "X-Filtered-By:")) 
  280. X          already_been_forwarded++;    /* could be a loop here! */
  281. X        else if (strlen(buffer) < 2) 
  282. X          in_header = 0;
  283. X        else if (whitespace(buffer[0]) && in_to)
  284. X          strcat(to, buffer);
  285. X      }
  286. X    
  287. X          fprintf(fd, "%s\n", buffer);    /* and save it regardless! */
  288. X      fflush(fd);
  289. X      lines++;
  290. X    }
  291. X
  292. X    fclose(fd);
  293. X
  294. X    /** next let's see if the user HAS a filter file, and if so what's in
  295. X            it (and so on) **/
  296. X
  297. X    if (get_filter_rules() == -1)
  298. X      mail_message(username);
  299. X    else {
  300. X      switch (action_from_ruleset()) {
  301. X
  302. X        case DELETE : if (verbose)
  303. X                printf("%sfilter (%s): Message deleted\n",
  304. X                    BEEP, username);
  305. X              log(DELETE);                    break;
  306. X
  307. X        case SAVE   : if (save_message(rules[rule_choosen].argument2)) {
  308. X                mail_message(username);
  309. X                log(FAILED_SAVE);
  310. X              }
  311. X              else
  312. X                 log(SAVE);                    break;
  313. X
  314. X        case SAVECC : if (save_message(rules[rule_choosen].argument2))
  315. X                log(FAILED_SAVE);
  316. X              else
  317. X                    log(SAVECC);                    
  318. X              mail_message(username);            break;
  319. X
  320. X        case FORWARD: mail_message(rules[rule_choosen].argument2);
  321. X              log(FORWARD);                    break;
  322. X
  323. X        case EXEC   : execute(rules[rule_choosen].argument2);
  324. X              log(EXEC);                    break;
  325. X
  326. X        case LEAVE  : mail_message(username);
  327. X              log(LEAVE);                    break;
  328. X      }
  329. X    }
  330. X
  331. X    (void) unlink(filename);    /* remove the temp file, please! */
  332. X    exit(0);    
  333. X}
  334. X
  335. Xsave_from(buffer)
  336. Xchar *buffer;
  337. X{
  338. X    /** save the SECOND word of this string as FROM **/
  339. X
  340. X    register int i, j;
  341. X
  342. X    for (i=0; buffer[i] != ' '; i++)     ;    /* get to word     */
  343. X
  344. X    for (i++, j=0; buffer[i] != ' ' && i < strlen(buffer); i++) 
  345. X      from[j++] = buffer[i];            /* copy it and     */
  346. X
  347. X    from[j++] = '\0';                /* Null terminate! */
  348. X}
  349. X
  350. Xsave_subject(buffer)
  351. Xchar *buffer;
  352. X{
  353. X    /** save all but the word "Subject:" for the subject **/
  354. X
  355. X    register int skip = 8;  /* skip "Subject:" initially */
  356. X
  357. X    while (buffer[skip] == ' ') skip++;
  358. X
  359. X    strcpy(subject, (char *) buffer + skip);
  360. X}
  361. X
  362. Xsave_to(buffer)
  363. Xchar *buffer;
  364. X{
  365. X    /** save all but the word "To:" for the to list **/
  366. X
  367. X    register int skip = 3;    /* skip "To:" initially */
  368. X
  369. X    while (buffer[skip] == ' ') skip++;
  370. X
  371. X    strcpy(to, (char *) buffer + skip);
  372. X}
  373. END_OF_filter/filter.c
  374. if test 5430 -ne `wc -c <filter/filter.c`; then
  375.     echo shar: \"filter/filter.c\" unpacked with wrong size!?
  376. fi
  377. # end of overwriting check
  378. fi
  379. echo shar: Extracting \"filter/utils2.c\" \(4993 characters\)
  380. if test -f filter/utils2.c ; then 
  381.   echo shar: Will not over-write existing file \"filter/utils2.c\"
  382. else
  383. sed "s/^X//" >filter/utils2.c <<'END_OF_filter/utils2.c'
  384. X/**            utils2.c            **/
  385. X
  386. X/** More miscellanous utilities for the filter program and such...
  387. X
  388. X    (C) Copyright 1986, Dave Taylor
  389. X**/
  390. X
  391. X#include <stdio.h>
  392. X
  393. X#ifdef BSD
  394. X# include <pwd.h>
  395. X#endif
  396. X
  397. X#ifdef NEED_GETHOSTNAME
  398. X#  include <sys/utsname.h>
  399. X#endif
  400. X
  401. X#ifdef NEED_GETHOSTNAME
  402. X
  403. Xgethostname(hostname,size) /* get name of current host */
  404. Xint size;
  405. Xchar *hostname;
  406. X{
  407. X    /** Return the name of the current host machine.  UTS only **/
  408. X
  409. X    /** This routine compliments of Scott McGregor at the HP
  410. X        Corporate Computing Center **/
  411. X     
  412. X    int uname();
  413. X    struct utsname name;
  414. X
  415. X    (void) uname(&name);
  416. X    (void) strncpy(hostname,name.nodename,size-1);
  417. X    hostname[size] = '\0';
  418. X
  419. X}
  420. X
  421. X#endif
  422. X
  423. X#ifdef BSD
  424. X
  425. X/** some supplementary string functions for Berkeley Unix systems **/
  426. X
  427. Xstrspn(source, keys)
  428. Xchar *source, *keys;
  429. X{
  430. X    /** This function returns the length of the substring of
  431. X        'source' (starting at zero) that consists ENTIRELY of
  432. X        characters from 'keys'.  This is used to skip over a
  433. X        defined set of characters with parsing, usually. 
  434. X    **/
  435. X
  436. X    register int loc = 0, key_index = 0;
  437. X
  438. X    while (source[loc] != '\0') {
  439. X      key_index = 0;
  440. X      while (keys[key_index] != source[loc])
  441. X        if (keys[key_index++] == '\0')
  442. X          return(loc);
  443. X      loc++;
  444. X    }
  445. X
  446. X    return(loc);
  447. X}
  448. X
  449. Xstrcspn(source, keys)
  450. Xchar *source, *keys;
  451. X{
  452. X    /** This function returns the length of the substring of
  453. X        'source' (starting at zero) that consists entirely of
  454. X        characters NOT from 'keys'.  This is used to skip to a
  455. X        defined set of characters with parsing, usually. 
  456. X        NOTE that this is the opposite of strspn() above
  457. X    **/
  458. X
  459. X    register int loc = 0, key_index = 0;
  460. X
  461. X    while (source[loc] != '\0') {
  462. X      key_index = 0;
  463. X      while (keys[key_index] != '\0')
  464. X        if (keys[key_index++] == source[loc])
  465. X          return(loc);
  466. X      loc++;
  467. X    }
  468. X
  469. X    return(loc);
  470. X}
  471. X
  472. Xchar *strtok(source, keys)
  473. Xchar *source, *keys;
  474. X{
  475. X    /** This function returns a pointer to the next word in source
  476. X        with the string considered broken up at the characters 
  477. X        contained in 'keys'.  Source should be a character pointer
  478. X        when this routine is first called, then NULL subsequently.
  479. X        When strtok has exhausted the source string, it will 
  480. X        return NULL as the next word. 
  481. X
  482. X        WARNING: This routine will DESTROY the string pointed to
  483. X        by 'source' when first invoked.  If you want to keep the
  484. X        string, make a copy before using this routine!!
  485. X     **/
  486. X
  487. X    register int  last_ch;
  488. X    static   char *sourceptr;
  489. X         char *return_value;
  490. X
  491. X    if (source != NULL)
  492. X      sourceptr = source;
  493. X    
  494. X    if (*sourceptr == '\0') 
  495. X      return(NULL);        /* we hit end-of-string last time!? */
  496. X
  497. X    sourceptr += strspn(sourceptr, keys);    /* skip leading crap */
  498. X    
  499. X    if (*sourceptr == '\0') 
  500. X      return(NULL);        /* we've hit end-of-string */
  501. X
  502. X    last_ch = strcspn(sourceptr, keys);    /* end of good stuff */
  503. X
  504. X    return_value = sourceptr;        /* and get the ret   */
  505. X
  506. X    sourceptr += last_ch;            /* ...value          */
  507. X
  508. X    if (*sourceptr != '\0')        /* don't forget if we're at END! */
  509. X      sourceptr++;               /* and skipping for next time */
  510. X
  511. X    return_value[last_ch] = '\0';        /* ..ending right    */
  512. X    
  513. X    return((char *) return_value);        /* and we're outta here! */
  514. X}
  515. X
  516. Xchar *strchr(buffer, ch)
  517. Xchar *buffer, ch;
  518. X{
  519. X    /** Returns a pointer to the first occurance of the character
  520. X        'ch' in the specified string or NULL if it doesn't occur **/
  521. X
  522. X    char *address;
  523. X
  524. X    address = buffer;
  525. X
  526. X    while (*address != ch) {
  527. X      if (*address == '\0')
  528. X        return (NULL);
  529. X      address++;
  530. X    }
  531. X
  532. X    return ( (char *) address);
  533. X}
  534. X
  535. X#endif
  536. X
  537. X#ifndef NULL
  538. X# define NULL        0
  539. X#endif
  540. X
  541. X#define DONE        0
  542. X#define ERROR        -1
  543. X
  544. Xchar *optional_arg;            /* optional argument as we go */
  545. Xint   opt_index;            /* argnum + 1 when we leave   */
  546. X
  547. Xint  _indx = 1, _argnum = 1;
  548. X
  549. Xint
  550. Xgetopt(argc, argv, options)
  551. Xint argc;
  552. Xchar *argv[], *options;
  553. X{
  554. X    /** Returns the character argument next, and optionally instantiates 
  555. X        "argument" to the argument associated with the particular option 
  556. X    **/
  557. X    
  558. X    char        *word, *strchr();
  559. X
  560. X    if (_argnum >= argc) {    /* quick check first - no arguments! */
  561. X      opt_index = argc;
  562. X      return(DONE);
  563. X    }
  564. X
  565. X    if (_indx >= strlen(argv[_argnum]) && _indx > 1) {
  566. X      _argnum++;
  567. X      _indx = 1;        /* zeroeth char is '-' */
  568. X    }
  569. X
  570. X    if (_argnum >= argc) {
  571. X      opt_index = _argnum; /* no more args */
  572. X      return(DONE);
  573. X    }
  574. X
  575. X    if (argv[_argnum][0] != '-') {
  576. X      opt_index = _argnum;
  577. X      return(DONE);
  578. X    }
  579. X
  580. X        word = strchr(options, argv[_argnum][_indx++]);
  581. X
  582. X    if (word == NULL)
  583. X      return(ERROR);        /* Sun compatibility */
  584. X
  585. X    if (word == NULL || strlen(word) == 0) 
  586. X      return(ERROR);
  587. X    
  588. X    if (word[1] == ':') {
  589. X
  590. X      /** Two possibilities - either tailing end of this argument or the 
  591. X          next argument in the list **/
  592. X
  593. X      if (_indx < strlen(argv[_argnum])) { /* first possibility */
  594. X        optional_arg = (char *) (argv[_argnum] + _indx);
  595. X        _argnum++;
  596. X        _indx = 1;
  597. X      }
  598. X      else {                /* second choice     */
  599. X        if (++_argnum >= argc) 
  600. X          return(ERROR);            /* no argument!!     */
  601. X
  602. X        optional_arg = (char *) argv[_argnum++];
  603. X        _indx = 1;
  604. X      }
  605. X    }
  606. X
  607. X    return((int) word[0]);
  608. X}
  609. END_OF_filter/utils2.c
  610. if test 4993 -ne `wc -c <filter/utils2.c`; then
  611.     echo shar: \"filter/utils2.c\" unpacked with wrong size!?
  612. fi
  613. # end of overwriting check
  614. fi
  615. echo shar: Extracting \"src/aliaslib.c\" \(4735 characters\)
  616. if test -f src/aliaslib.c ; then 
  617.   echo shar: Will not over-write existing file \"src/aliaslib.c\"
  618. else
  619. sed "s/^X//" >src/aliaslib.c <<'END_OF_src/aliaslib.c'
  620. X/**            aliaslib.c            **/
  621. X
  622. X/** Library of functions dealing with the alias system...
  623. X
  624. X    (C) Copyright 1986 Dave Taylor
  625. X **/
  626. X
  627. X#include "headers.h"
  628. X
  629. Xchar *expand_group(), *get_alias_address(), *expand_system();
  630. Xchar *get_token(), *strpbrk();
  631. Xlong lseek();
  632. X
  633. Xchar *get_alias_address(name, mailing, depth)
  634. Xchar *name;
  635. Xint   mailing, depth;
  636. X{
  637. X    /** return the line from either datafile that corresponds 
  638. X        to the specified name.  If 'mailing' specified, then
  639. X        fully expand group names.  Depth specifies the nesting
  640. X        depth - the routine should always initially be called
  641. X        with this equal 0.  Returns NULL if not found   **/
  642. X
  643. X    static char buffer[VERY_LONG_STRING];
  644. X    int    loc;
  645. X
  646. X    if (strlen(name) == 0)
  647. X      return( (char *) NULL);
  648. X
  649. X    if (! read_in_aliases) {
  650. X      read_alias_files();
  651. X      read_in_aliases = TRUE;
  652. X    }
  653. X
  654. X    if (user_files) 
  655. X      if ((loc = find(name, user_hash_table, MAX_UALIASES)) >= 0) {
  656. X        lseek(user_data, user_hash_table[loc].byte, 0L);
  657. X        get_line(user_data, buffer);
  658. X        if (buffer[0] == '!' && mailing)
  659. X          return(expand_group(buffer, depth));
  660. X        else if (strpbrk(buffer,"!@:") != NULL)    /* has a hostname */
  661. X#ifdef DONT_TOUCH_ADDRESSES
  662. X          return((char *) buffer);
  663. X#else
  664. X          return(expand_system(buffer, TRUE));
  665. X#endif
  666. X        else
  667. X          return((char *) buffer);
  668. X      }
  669. X     
  670. X    if (system_files) 
  671. X      if ((loc = find(name, system_hash_table, MAX_SALIASES)) >= 0) {
  672. X        lseek(system_data, system_hash_table[loc].byte, 0L);
  673. X        get_line(system_data, buffer);
  674. X        if (buffer[0] == '!' && mailing)
  675. X          return(expand_group(buffer, depth));
  676. X        else if (strpbrk(buffer,"!@:") != NULL)    /* has a hostname */
  677. X#ifdef DONT_TOUCH_ADDRESSES
  678. X          return((char *) buffer);
  679. X#else
  680. X          return(expand_system(buffer, TRUE));
  681. X#endif
  682. X        else
  683. X          return((char *) buffer);
  684. X      }
  685. X    
  686. X    return( (char *) NULL);
  687. X}
  688. X
  689. Xchar *expand_system(buffer, show_errors)
  690. Xchar *buffer;
  691. Xint   show_errors;
  692. X{
  693. X    /** This routine will check the first machine name in the given path 
  694. X        (if any) and expand it out if it is an alias...if not, it will 
  695. X        return what it was given.  If show_errors is false, it won't 
  696. X        display errors encountered...
  697. X    **/
  698. X
  699. X    dprint2(6, "expand_system(%s, show-errors=%s)\n", buffer,
  700. X        onoff(show_errors));
  701. X    findnode(buffer, show_errors);
  702. X
  703. X    return( (char *) buffer);
  704. X}
  705. X          
  706. Xchar *expand_group(members, depth)
  707. Xchar *members;
  708. Xint  depth;
  709. X{
  710. X    /** Given a group of names separated by commas, this routine
  711. X        will return a string that is the full addresses of each
  712. X        member separated by spaces. Depth is an internal counter
  713. X        that keeps track of the depth of nesting that the routine
  714. X        is in...it's for the get_token routine!  **/
  715. X
  716. X    static char buffer[VERY_LONG_STRING];
  717. X    char   buf[LONG_STRING], *word, *address, *bufptr;
  718. X    char   *strcpy();
  719. X
  720. X    strcpy(buf, members);             /* parameter safety! */
  721. X    if (depth == 0) buffer[0] = '\0';    /* nothing in yet!   */
  722. X    bufptr = (char *) buf;            /* grab the address  */
  723. X    depth++;                /* one deeper!       */
  724. X
  725. X    while ((word = get_token(bufptr, "!, ", depth)) != NULL) {
  726. X      if ((address = get_alias_address(word, 1, depth)) == NULL) {
  727. X        if (! valid_name(word)) {
  728. X          dprint2(3, "Encountered illegal address %s (%s)\n",
  729. X            word, "expand_group");
  730. X          error1("%s is an illegal address!", word);
  731. X          return( (char *) NULL);
  732. X        }
  733. X        else if (strcmp(buffer, word) != 0)
  734. X          sprintf(buffer, "%s%s%s", buffer,
  735. X            (strlen(buffer) > 0)? ", ":"", word);
  736. X      }
  737. X      else if (strcmp(buffer, address) != 0)
  738. X        sprintf(buffer,"%s%s%s", buffer, 
  739. X            (strlen(buffer) > 0)? ", ":"", address);
  740. X
  741. X      bufptr = NULL;
  742. X    }
  743. X
  744. X    return( (char *) buffer);
  745. X}
  746. X
  747. Xint
  748. Xfind(word, table, size)
  749. Xchar *word;
  750. Xstruct alias_rec table[];
  751. Xint size;
  752. X{
  753. X    /** find word and return loc, or -1 **/
  754. X    register int loc;
  755. X    
  756. X    if (strlen(word) > 20) {
  757. X      dprint2(3, "Too long alias name entered [%s] (%s)\n", word, "find");
  758. X      error1("Bad alias name: %s.  Too long.\n", word);
  759. X      return(-1);
  760. X    }
  761. X
  762. X    loc = hash_it(word, size);
  763. X
  764. X    while (strcmp(word, table[loc].name) != 0) {
  765. X      if (table[loc].name[0] == '\0')
  766. X        return(-1);
  767. X      loc = (loc + 1) % size; 
  768. X    }
  769. X
  770. X    return(loc);
  771. X}
  772. X
  773. Xint
  774. Xhash_it(string, table_size)
  775. Xchar *string;
  776. Xint   table_size;
  777. X{
  778. X    /** compute the hash function of the string, returning
  779. X        it (mod table_size) **/
  780. X
  781. X    register int i, sum = 0;
  782. X    
  783. X    for (i=0; string[i] != '\0'; i++)
  784. X      sum += (int) string[i];
  785. X
  786. X    return(sum % table_size);
  787. X}
  788. X
  789. Xget_line(fd, buffer)
  790. Xint fd;
  791. Xchar *buffer;
  792. X{
  793. X    /* Read from file fd.  End read upon reading either 
  794. X       EOF or '\n' character (this is where it differs 
  795. X       from a straight 'read' command!) */
  796. X
  797. X    register int i= 0;
  798. X    char     ch;
  799. X
  800. X    while (read(fd, &ch, 1) > 0)
  801. X      if (ch == '\n' || ch == '\r') {
  802. X        buffer[i] = 0;
  803. X        return;
  804. X      }
  805. X      else
  806. X        buffer[i++] = ch;
  807. X}
  808. END_OF_src/aliaslib.c
  809. if test 4735 -ne `wc -c <src/aliaslib.c`; then
  810.     echo shar: \"src/aliaslib.c\" unpacked with wrong size!?
  811. fi
  812. # end of overwriting check
  813. fi
  814. echo shar: Extracting \"src/edit.c\" \(5274 characters\)
  815. if test -f src/edit.c ; then 
  816.   echo shar: Will not over-write existing file \"src/edit.c\"
  817. else
  818. sed "s/^X//" >src/edit.c <<'END_OF_src/edit.c'
  819. X/**            edit.c            **/
  820. X
  821. X/** This routine is for allowing the user to edit their current mailbox
  822. X    as they wish. 
  823. X
  824. X    (C) Copyright 1986 Dave Taylor
  825. X**/
  826. X
  827. X#include "headers.h"
  828. X#include <errno.h>
  829. X#include <sys/types.h>
  830. X#include <sys/stat.h>
  831. X
  832. Xextern int errno;
  833. X
  834. Xchar   *error_name(), *error_description(), *strcpy();
  835. Xlong   bytes();
  836. Xunsigned long sleep();
  837. X
  838. Xedit_mailbox()
  839. X{
  840. X    /** Allow the user to edit their mailbox, always resynchronizing
  841. X        afterwards.   Due to intense laziness on the part of the
  842. X        programmer, this routine will invoke $EDITOR on the entire
  843. X        file.  The mailer will ALWAYS resync on the mailbox file
  844. X        even if nothing has changed since, not unreasonably, it's
  845. X        hard to figure out what occurred in the edit session...
  846. X    
  847. X        Also note that if the user wants to edit their incoming
  848. X        mailbox they'll actually be editing the tempfile that is
  849. X        an exact copy.  More on how we resync in that case later
  850. X        in this code.
  851. X    **/
  852. X
  853. X    FILE     *real_mailbox, *temp_mailbox;
  854. X    char     filename[SLEN], buffer[LONG_SLEN], temp_infile[SLEN];
  855. X    struct   stat stat_buffer;
  856. X    int      loaded_stat_buffer = FALSE;
  857. X
  858. X    PutLine0(LINES-1,0,"invoking editor...");
  859. X
  860. X    if (mbox_specified == 0) {
  861. X      sprintf(filename, "%s%s", temp_mbox, username);
  862. X      chown(filename, userid, groupid);        /* make sure we can! */
  863. X    }
  864. X    else 
  865. X      strcpy(filename, infile);
  866. X
  867. X    /** now get and save the ownership and permissions... **/
  868. X
  869. X    if (stat(infile, &stat_buffer)) {
  870. X      error("Warning: couldn't 'stat' file, perms might get mangled");
  871. X      sleep(2);
  872. X    }
  873. X    else
  874. X      loaded_stat_buffer = TRUE;
  875. X
  876. X    sprintf(buffer, "%s %s", alternative_editor, filename);
  877. X
  878. X    Raw(OFF);
  879. X
  880. X    if (system_call(buffer, SH) != 0) {
  881. X      error1("Problems invoking editor %s!", alternative_editor);
  882. X      Raw(ON);
  883. X      sleep(2);
  884. X      return(0);
  885. X    }
  886. X
  887. X    Raw(ON);
  888. X
  889. X    if (mbox_specified == 0) {    /* uh oh... now the toughie...  */
  890. X
  891. X      sprintf(temp_infile, "%s%s.temp", mailhome, username);
  892. X      unlink(temp_infile);    /* remove it if it's there... */
  893. X
  894. X      if (bytes(infile) != mailfile_size) {
  895. X
  896. X         /* SIGH.  We've received mail since we invoked the editor
  897. X        on the mailbox.  We'll have to do some strange stuff to
  898. X            remedy the problem... */
  899. X
  900. X         PutLine0(LINES, 0, "Warning: new mail received...");
  901. X         CleartoEOLN();
  902. X
  903. X         if ((temp_mailbox = fopen(filename, "a")) == NULL) {
  904. X        dprint2(1, "Attempt to open %s to append failed! (%s)\n", 
  905. X            filename, "edit_mailbox");
  906. X           set_error("Couldn't reopen tempfile.  Edit LOST!");
  907. X           return(1);
  908. X         }
  909. X         /** Now let's lock the mailbox up and stream the new stuff 
  910. X         into the temp file... **/
  911. X
  912. X         lock(OUTGOING);    
  913. X         if ((real_mailbox = fopen(infile, "r")) == NULL) {
  914. X           dprint2(1, 
  915. X               "Attempt to open %s for reading new mail failed! (%s)\n",
  916. X              infile, "edit_mailbox");
  917. X           sprintf(buffer, "Couldn't open %s for reading!  Edit LOST!", 
  918. X               infile);
  919. X           set_error(buffer);
  920. X           unlock();
  921. X           return(1);
  922. X         }
  923. X         if (fseek(real_mailbox, mailfile_size, 0) != 0) {
  924. X           dprint2(1, "Couldn't seek to end of infile (offset %ld) (%s)\n",
  925. X            mailfile_size, "edit_mailbox");
  926. X           set_error("Couldn't seek to end of mailbox.  Edit LOST!");
  927. X           unlock();
  928. X           return(1);
  929. X         }
  930. X    
  931. X         /** Now we can finally stream the new mail into the tempfile **/
  932. X
  933. X         while (fgets(buffer, LONG_SLEN, real_mailbox) != NULL)
  934. X           fprintf(temp_mailbox, "%s", buffer);
  935. X
  936. X         fclose(real_mailbox);
  937. X         fclose(temp_mailbox);
  938. X        }
  939. X       else
  940. X         lock(OUTGOING); /* create a lock file if we're replacing mailbox */
  941. X
  942. X       /** link to the temporary mailbox in the mailhome directory... **/
  943. X
  944. X       if (link(filename, temp_infile) != 0) 
  945. X         if (errno == EXDEV) {   /* attempt to link across file systems */
  946. X              if (copy(filename, temp_infile) != 0) {
  947. X             error("Couldn't copy temp file to mailbox!");
  948. X             unlock();                    /* ciao!*/
  949. X            emergency_exit();
  950. X           }
  951. X         }
  952. X         else {
  953. X        Write_to_screen("\n\rCouldn't link %s to mailfile %s...\n\r",2,
  954. X            filename, temp_infile);
  955. X        Write_to_screen("** %s - %s **\n\r", 2,
  956. X            error_name(errno), error_description(errno));
  957. X            emergency_exit();
  958. X         }
  959. X    
  960. X       /***  G U L P ... let's remove the incoming mail file... ***/
  961. X         
  962. X       unlink(infile);
  963. X
  964. X       /** and quickly now... **/
  965. X
  966. X       if (link(temp_infile, infile) != 0) {
  967. X         Write_to_screen(
  968. X            "\n\rCouldn't internally link %s to mailfile %s...\n\r",
  969. X            2, temp_infile, infile);
  970. X         Write_to_screen(
  971. X            "\n\rYou'll need to check out %s for your mail...\n\r",
  972. X            1, temp_infile);
  973. X         Write_to_screen("** %s - %s **\n\r", 2,
  974. X            error_name(errno), error_description(errno));
  975. X         emergency_exit();
  976. X       }
  977. X
  978. X       /** And let's remove the lock file!  We're DONE!!!  **/
  979. X
  980. X       unlock();
  981. X       unlink(temp_infile);    /* remove the temp file too */
  982. X       unlink(filename);    /* remove the temp file too */
  983. X       error("edit changes incorporated into new mail...");
  984. X    }
  985. X    else
  986. X      error("Resynchronizing with new version of mailbox...");
  987. X
  988. X    sleep(2);
  989. X    resync();
  990. X
  991. X    current = 1;        /* don't leave the user hanging! */
  992. X
  993. X    /** finally restore the permissions... **/
  994. X
  995. X    if (loaded_stat_buffer) {    /* if not, it's junk! */
  996. X      chown(infile, stat_buffer.st_uid, stat_buffer.st_gid);
  997. X      chmod(infile, stat_buffer.st_mode);
  998. X    }
  999. X
  1000. X    return(1);
  1001. X}
  1002. END_OF_src/edit.c
  1003. if test 5274 -ne `wc -c <src/edit.c`; then
  1004.     echo shar: \"src/edit.c\" unpacked with wrong size!?
  1005. fi
  1006. # end of overwriting check
  1007. fi
  1008. echo shar: Extracting \"src/file_utils.c\" \(5169 characters\)
  1009. if test -f src/file_utils.c ; then 
  1010.   echo shar: Will not over-write existing file \"src/file_utils.c\"
  1011. else
  1012. sed "s/^X//" >src/file_utils.c <<'END_OF_src/file_utils.c'
  1013. X/**            file_utils.c            **/
  1014. X
  1015. X/** File oriented utility routines for ELM 
  1016. X
  1017. X    (C) Copyright 1986 Dave Taylor
  1018. X**/
  1019. X
  1020. X#include "headers.h"
  1021. X#include <sys/types.h>
  1022. X#include <sys/stat.h>
  1023. X#include <ctype.h>
  1024. X#include <errno.h>
  1025. X
  1026. X#ifdef BSD
  1027. X# undef tolower
  1028. X#endif
  1029. X
  1030. X#include <signal.h>
  1031. X#include <errno.h>
  1032. X
  1033. X#ifdef BSD
  1034. X# include <sys/wait.h>
  1035. X#endif
  1036. X
  1037. Xextern int errno;        /* system error number */
  1038. X
  1039. Xchar *error_name(), *error_description(), *strcpy(), *getlogin();
  1040. X
  1041. Xlong
  1042. Xbytes(name)
  1043. Xchar *name;
  1044. X{
  1045. X    /** return the number of bytes in the specified file.  This
  1046. X        is to check to see if new mail has arrived....  **/
  1047. X
  1048. X    int ok = 1;
  1049. X    extern int errno;    /* system error number! */
  1050. X    struct stat buffer;
  1051. X
  1052. X    if (stat(name, &buffer) != 0)
  1053. X      if (errno != 2) {
  1054. X        dprint2(1,"Error: errno %s on fstat of file %s (bytes)\n", 
  1055. X             error_name(errno), name);
  1056. X        Write_to_screen("\n\rError attempting fstat on file %s!\n\r",
  1057. X             1, name);
  1058. X        Write_to_screen("** %s - %s **\n\r", 2, error_name(errno),
  1059. X          error_description(errno));
  1060. X        emergency_exit();
  1061. X      }
  1062. X      else
  1063. X        ok = 0;
  1064. X    
  1065. X    return(ok ? (long) buffer.st_size : 0L);
  1066. X}
  1067. X
  1068. Xint
  1069. Xcan_access(file, mode)
  1070. Xchar *file; 
  1071. Xint   mode;
  1072. X{
  1073. X    /** returns ZERO iff user can access file or "errno" otherwise **/
  1074. X
  1075. X    int the_stat = 0, pid, w; 
  1076. X    void _exit(), exit();
  1077. X#ifdef BSD
  1078. X    union wait status;
  1079. X#else
  1080. X    int status;
  1081. X#endif
  1082. X    register int (*istat)(), (*qstat)();
  1083. X    
  1084. X#ifdef NO_VM        /* machine without virtual memory!! */
  1085. X    if ((pid = fork()) == 0) {
  1086. X#else
  1087. X    if ((pid = vfork()) == 0) {
  1088. X#endif
  1089. X      setgid(groupid);
  1090. X      setuid(userid);        /** back to normal userid **/
  1091. X
  1092. X      errno = 0;
  1093. X
  1094. X      if (access(file, mode) == 0) 
  1095. X        _exit(0);
  1096. X      else 
  1097. X        _exit(errno != 0? errno : 1);    /* never return zero! */
  1098. X      _exit(127);
  1099. X    }
  1100. X
  1101. X    istat = signal(SIGINT, SIG_IGN);
  1102. X    qstat = signal(SIGQUIT, SIG_IGN);
  1103. X
  1104. X    while ((w = wait(&status)) != pid && w != -1)
  1105. X        ;
  1106. X
  1107. X#ifdef BSD
  1108. X    the_stat = status.w_retcode;
  1109. X#else
  1110. X    the_stat = status;
  1111. X#endif
  1112. X
  1113. X    signal(SIGINT, istat);
  1114. X    signal(SIGQUIT, qstat);
  1115. X
  1116. X    return(the_stat);
  1117. X}
  1118. X
  1119. Xint
  1120. Xcan_open(file, mode)
  1121. Xchar *file, *mode;
  1122. X{
  1123. X    /** Returns 0 iff user can open the file.  This is not
  1124. X        the same as can_access - it's used for when the file might
  1125. X        not exist... **/
  1126. X
  1127. X    FILE *fd;
  1128. X    int the_stat = 0, pid, w; 
  1129. X    void _exit(), exit();
  1130. X#ifdef BSD
  1131. X    union wait status;
  1132. X#else
  1133. X    int status;
  1134. X#endif
  1135. X    register int (*istat)(), (*qstat)();
  1136. X    
  1137. X#ifdef NO_VM        /* machine without virtual memory!! */
  1138. X    if ((pid = fork()) == 0) {
  1139. X#else
  1140. X    if ((pid = vfork()) == 0) {
  1141. X#endif
  1142. X      setgid(groupid);
  1143. X      setuid(userid);        /** back to normal userid **/
  1144. X      errno = 0;
  1145. X      if ((fd = fopen(file, mode)) == NULL)
  1146. X        _exit(errno);
  1147. X      else {
  1148. X        fclose(fd);        /* don't just LEAVE it! */
  1149. X        _exit(0);
  1150. X      }
  1151. X      _exit(127);
  1152. X    }
  1153. X
  1154. X    istat = signal(SIGINT, SIG_IGN);
  1155. X    qstat = signal(SIGQUIT, SIG_IGN);
  1156. X
  1157. X    while ((w = wait(&status)) != pid && w != -1)
  1158. X        ;
  1159. X
  1160. X#ifdef BSD
  1161. X    the_stat = status.w_retcode;
  1162. X#else
  1163. X    the_stat = status;
  1164. X#endif
  1165. X    
  1166. X    signal(SIGINT, istat);
  1167. X    signal(SIGQUIT, qstat);
  1168. X
  1169. X    return(the_stat);
  1170. X}
  1171. X
  1172. Xint
  1173. Xcopy(from, to)
  1174. Xchar *from, *to;
  1175. X{
  1176. X    /** this routine copies a specified file to the destination
  1177. X        specified.  Non-zero return code indicates that something
  1178. X        dreadful happened! **/
  1179. X
  1180. X    FILE *from_file, *to_file;
  1181. X    char buffer[VERY_LONG_STRING];
  1182. X    
  1183. X    if ((from_file = fopen(from, "r")) == NULL) {
  1184. X      dprint1(1,"Error: could not open %s for reading (copy)\n", from);
  1185. X      error1("could not open file %s", from);
  1186. X      return(1);
  1187. X    }
  1188. X
  1189. X    if ((to_file = fopen(to, "w")) == NULL) {
  1190. X      dprint1(1,"Error: could not open %s for writing (copy)\n", to);
  1191. X      error1("could not open file %s", to);
  1192. X      return(1);
  1193. X    }
  1194. X
  1195. X    while (fgets(buffer, VERY_LONG_STRING, from_file) != NULL)
  1196. X      fputs(buffer, to_file);
  1197. X
  1198. X    fclose(from_file);
  1199. X    fclose(to_file);
  1200. X
  1201. X    return(0);
  1202. X}
  1203. X
  1204. Xint
  1205. Xappend(fd, filename)
  1206. XFILE *fd;
  1207. Xchar *filename;
  1208. X{
  1209. X    /** This routine appends the specified file to the already
  1210. X        open file descriptor.. Returns non-zero if fails.  **/
  1211. X
  1212. X    FILE *my_fd;
  1213. X    char buffer[VERY_LONG_STRING];
  1214. X    
  1215. X    if ((my_fd = fopen(filename, "r")) == NULL) {
  1216. X      dprint1(1,"Error: could not open %s for reading (append)\n", filename);
  1217. X      return(1);
  1218. X    }
  1219. X
  1220. X    while (fgets(buffer, VERY_LONG_STRING, my_fd) != NULL)
  1221. X      fputs(buffer, fd);
  1222. X
  1223. X    fclose(my_fd);
  1224. X
  1225. X    return(0);
  1226. X}
  1227. X
  1228. Xcheck_mailfile_size()
  1229. X{
  1230. X    /** Check to ensure we have mail.  Only used with the '-z'
  1231. X        starting option. **/
  1232. X
  1233. X    char filename[SLEN], *getlogin();
  1234. X    struct stat buffer;
  1235. X
  1236. X    strcpy(username,getlogin());
  1237. X    if (strlen(username) == 0)
  1238. X      cuserid(username);
  1239. X
  1240. X    sprintf(filename,"%s%s", mailhome, username);
  1241. X
  1242. X    if (stat(filename, &buffer) == -1) {
  1243. X      printf(" You have no mail.\n");
  1244. X      exit(0);
  1245. X    }
  1246. X    else if (buffer.st_size < 2) {         /* maybe one byte??? */
  1247. X      printf("You have no mail to read.\n");
  1248. X      exit(0);
  1249. X    }
  1250. X}
  1251. X
  1252. Xcreate_readmsg_file()
  1253. X{
  1254. X    /** Creates the file ".current" in the users home directory
  1255. X        for use with the "readmsg" program.
  1256. X    **/
  1257. X
  1258. X    FILE *fd;
  1259. X    char buffer[SLEN];
  1260. X
  1261. X    sprintf(buffer,"%s/%s", home, readmsg_file);
  1262. X
  1263. X    if ((fd = fopen (buffer, "w")) == NULL) {
  1264. X      dprint3(1,"Error: couldn't create file %s - error %s (%s)\n",
  1265. X         buffer, error_name(errno), "create_readmsg_file");
  1266. X      return;    /* no error to user */
  1267. X    }
  1268. X
  1269. X    fprintf(fd, "%d\n", header_table[current-1].index_number);
  1270. X    fclose(fd);
  1271. X}
  1272. END_OF_src/file_utils.c
  1273. if test 5169 -ne `wc -c <src/file_utils.c`; then
  1274.     echo shar: \"src/file_utils.c\" unpacked with wrong size!?
  1275. fi
  1276. # end of overwriting check
  1277. fi
  1278. echo shar: Extracting \"src/mailtime.c\" \(4749 characters\)
  1279. if test -f src/mailtime.c ; then 
  1280.   echo shar: Will not over-write existing file \"src/mailtime.c\"
  1281. else
  1282. sed "s/^X//" >src/mailtime.c <<'END_OF_src/mailtime.c'
  1283. X/**            mailtime.c            **/
  1284. X
  1285. X/** This set of routines is used to figure out when the user last read
  1286. X    their mail and to also figure out if a given message is new or not.
  1287. X
  1288. X    (C) Copyright 1986 Dave Taylor
  1289. X**/
  1290. X
  1291. X#include "headers.h"
  1292. X
  1293. X#include <sys/types.h>
  1294. X#include <sys/stat.h>
  1295. X#ifdef BSD
  1296. X#  ifndef BSD4.1
  1297. X#    include <sys/time.h>
  1298. X#  else
  1299. X#    include <time.h>
  1300. X#    include <sys/timeb.h>
  1301. X#  endif
  1302. X#else
  1303. X#  include <time.h>
  1304. X#endif
  1305. X
  1306. Xresolve_received(entry)
  1307. Xstruct header_rec *entry;
  1308. X{
  1309. X    /** Entry has the data for computing the time and date the 
  1310. X        message was received.  Fix it and return **/
  1311. X
  1312. X    switch (tolower(entry->month[0])) {
  1313. X      case 'j' : if (tolower(entry->month[1]) == 'a')
  1314. X               entry->received.month = JANUARY;
  1315. X             else if (tolower(entry->month[2]) == 'n')
  1316. X                   entry->received.month = JUNE;
  1317. X             else
  1318. X                   entry->received.month = JULY;
  1319. X                 break;
  1320. X      case 'f' : entry->received.month = FEBRUARY;
  1321. X              break;
  1322. X      case 'm' : if (tolower(entry->month[2]) == 'r')
  1323. X                   entry->received.month = MARCH;
  1324. X             else
  1325. X               entry->received.month = MAY;
  1326. X                 break;
  1327. X      case 'a' : if (tolower(entry->month[1]) == 'p')
  1328. X                   entry->received.month = APRIL;
  1329. X                 else
  1330. X                   entry->received.month = AUGUST;
  1331. X             break;
  1332. X      case 's' : entry->received.month = SEPTEMBER;
  1333. X             break;
  1334. X      case 'o' : entry->received.month = OCTOBER;
  1335. X             break;
  1336. X      case 'n' : entry->received.month = NOVEMBER;
  1337. X               break;
  1338. X      case 'd' : entry->received.month = DECEMBER;
  1339. X             break;
  1340. X    }
  1341. X
  1342. X    sscanf(entry->day, "%d", &(entry->received.day));
  1343. X
  1344. X    sscanf(entry->year, "%d", &(entry->received.year));
  1345. X    if (entry->received.year > 100) entry->received.year -= 1900;
  1346. X
  1347. X    sscanf(entry->time, "%d:%d", &(entry->received.hour),
  1348. X           &(entry->received.minute));
  1349. X}
  1350. X
  1351. Xget_mailtime()
  1352. X{
  1353. X    /** Instantiate the values of the last_read_mail stat
  1354. X        variable based on the file access time/date of the
  1355. X        file mailtime_file.  IF the file doesn't exist,
  1356. X        then assume all mail is new. **/
  1357. X
  1358. X    struct stat buffer;
  1359. X    struct tm   *timebuf;
  1360. X    char   filename[SLEN];
  1361. X#ifdef BSD
  1362. X    extern struct tm *localtime();
  1363. X#endif
  1364. X
  1365. X    sprintf(filename, "%s/%s", home, mailtime_file);
  1366. X
  1367. X    if (stat(filename, &buffer) == -1) {
  1368. X      last_read_mail.month = 0;
  1369. X      last_read_mail.day = 0;
  1370. X      last_read_mail.year = 0;
  1371. X      last_read_mail.hour = 0;
  1372. X      last_read_mail.minute = 0;
  1373. X    }
  1374. X    else {    /* stat okay... */
  1375. X      timebuf = (struct tm *) localtime(&(buffer.st_mtime));
  1376. X      
  1377. X      last_read_mail.month = timebuf->tm_mon;
  1378. X      last_read_mail.day = timebuf->tm_mday;
  1379. X      last_read_mail.year = timebuf->tm_year;
  1380. X      last_read_mail.hour = timebuf->tm_hour;
  1381. X      last_read_mail.minute = timebuf->tm_min;
  1382. X    }
  1383. X}
  1384. X
  1385. Xupdate_mailtime()
  1386. X{
  1387. X    /** This routine updates the last modified time of the 
  1388. X        .last_read_mail file in the users home directory.
  1389. X        If the file doesn't exist, it creates it!! **/
  1390. X
  1391. X    char filename[SLEN];
  1392. X
  1393. X#ifdef BSD
  1394. X# ifdef BSD4.1
  1395. X    struct timeb  loc_time;
  1396. X    time_t tval;
  1397. X# else
  1398. X    struct timeval    tval[2];
  1399. X    struct timezone tzone;
  1400. X# endif
  1401. X#endif
  1402. X    
  1403. X    sprintf(filename, "%s/%s", home, mailtime_file);
  1404. X
  1405. X#ifdef BSD
  1406. X# ifdef BSD4.1
  1407. X    tval = (time_t) time((long *) 0);
  1408. X    if (utime(filename, &tval) == -1)
  1409. X# else
  1410. X    gettimeofday(&tval[0], &tzone);
  1411. X    gettimeofday(&tval[1], &tzone);
  1412. X
  1413. X    if (utimes(filename, tval) == -1)    /* note the "S" */
  1414. X# endif
  1415. X#else
  1416. X    if (utime(filename, NULL) == -1)    /* note no "S"  */
  1417. X#endif
  1418. X    /** That's what I like about programming for BSD & USG - the easy
  1419. X        portability between 'em.  Especially the section 2 calls!! **/
  1420. X
  1421. X      (void) creat(filename, 0777);
  1422. X}
  1423. X
  1424. Xnew_msg(entry)
  1425. Xstruct header_rec entry;
  1426. X{
  1427. X    /** Return true if the current message is NEW.  This can be
  1428. X        easily tested by seeing 1) if we're reading the incoming
  1429. X        mailbox and then, if so, 2) if the received_on_machine
  1430. X        date is more recent than the last_read_mail date.
  1431. X    **/
  1432. X
  1433. X    if (mbox_specified != 0) return(FALSE);        /* not incoming */
  1434. X    
  1435. X    /** Two tests - if received is OLDER than last read mail, then
  1436. X        immediately return FALSE.  If received is NEWER than last
  1437. X        read mail then immediately return TRUE **/
  1438. X
  1439. X    if (entry.received.year < last_read_mail.year) 
  1440. X      return(FALSE);                
  1441. X    
  1442. X    if (entry.received.year > last_read_mail.year) 
  1443. X      return(TRUE);                
  1444. X    
  1445. X    if (entry.received.month < last_read_mail.month)
  1446. X      return(FALSE);            
  1447. X
  1448. X    if (entry.received.month > last_read_mail.month)
  1449. X      return(TRUE);            
  1450. X
  1451. X    if (entry.received.day < last_read_mail.day)
  1452. X      return(FALSE);
  1453. X
  1454. X    if (entry.received.day > last_read_mail.day)
  1455. X      return(TRUE);
  1456. X
  1457. X    if (entry.received.hour < last_read_mail.hour)        
  1458. X      return(FALSE);        
  1459. X    
  1460. X    if (entry.received.hour > last_read_mail.hour)        
  1461. X      return(TRUE);        
  1462. X    
  1463. X    if (entry.received.minute < last_read_mail.minute)
  1464. X      return(FALSE);    
  1465. X
  1466. X    return(TRUE);
  1467. X}
  1468. END_OF_src/mailtime.c
  1469. if test 4749 -ne `wc -c <src/mailtime.c`; then
  1470.     echo shar: \"src/mailtime.c\" unpacked with wrong size!?
  1471. fi
  1472. # end of overwriting check
  1473. fi
  1474. echo shar: Extracting \"src/opt_utils.c\" \(5098 characters\)
  1475. if test -f src/opt_utils.c ; then 
  1476.   echo shar: Will not over-write existing file \"src/opt_utils.c\"
  1477. else
  1478. sed "s/^X//" >src/opt_utils.c <<'END_OF_src/opt_utils.c'
  1479. X/**            opt_utils.c            **/
  1480. X
  1481. X/** This file contains routines that might be needed for the various
  1482. X     machines that the mailer can run on.  Please check the Makefile
  1483. X     for more help and/or information. 
  1484. X
  1485. X     (C) Copyright 1986 Dave Taylor
  1486. X**/
  1487. X
  1488. X#include <stdio.h>
  1489. X#include "headers.h"
  1490. X
  1491. X#ifdef BSD
  1492. X# include <pwd.h>
  1493. X#endif
  1494. X
  1495. X#ifdef NEED_GETHOSTNAME
  1496. X#  include <sys/utsname.h>
  1497. X#endif
  1498. X
  1499. X#ifdef UTS
  1500. X# include <sys/tubio.h>
  1501. X# define  TTYIN        0        /* standard input */
  1502. X#endif
  1503. X
  1504. X#ifdef NEED_GETHOSTNAME
  1505. X
  1506. Xgethostname(hostname,size) /* get name of current host */
  1507. Xint size;
  1508. Xchar *hostname;
  1509. X{
  1510. X    /** Return the name of the current host machine.  UTS only **/
  1511. X
  1512. X    /** This routine compliments of Scott McGregor at the HP
  1513. X        Corporate Computing Center **/
  1514. X     
  1515. X    int uname();
  1516. X    struct utsname name;
  1517. X
  1518. X    (void) uname(&name);
  1519. X    (void) strncpy(hostname,name.nodename,size-1);
  1520. X    hostname[size] = '\0';
  1521. X
  1522. X}
  1523. X
  1524. X#endif
  1525. X
  1526. X#ifdef UTS
  1527. X
  1528. Xint
  1529. Xisa3270()
  1530. X{
  1531. X    /** Returns TRUE and sets LINES and COLUMNS to the correct values
  1532. X        for an Amdahl (IBM) tube screen, or returns FALSE if on a normal
  1533. X        terminal (of course, next to a 3270, ANYTHING is normal!!) **/
  1534. X
  1535. X    struct tubiocb tubecb;
  1536. X
  1537. X    dprint0(3,"Seeing if we're a 3270...");
  1538. X
  1539. X    if (ioctl(TTYIN, TUBGETMOD, &tubecb) == -1) {
  1540. X      dprint0(3,"We're not!\n");
  1541. X      return(FALSE);    /* not a tube! */
  1542. X    }
  1543. X    
  1544. X    LINES   = tubecb->line_cnt - 1;
  1545. X    COLUMNS = tubecb->col_cnt;
  1546. X    
  1547. X    dprint2(3,"We are!  %d lines and %d columns!\n",
  1548. X        LINES, COLUMNS);
  1549. X    return(TRUE);
  1550. X}
  1551. X
  1552. X#endif /* def UTS */
  1553. X
  1554. X#ifdef BSD
  1555. X
  1556. Xcuserid(uname)
  1557. Xchar *uname;
  1558. X{
  1559. X    /** Added for compatibility with Bell systems, this is the last-ditch
  1560. X        attempt to get the users login name, after getlogin() fails.  It
  1561. X        instantiates "uname" to the name of the user...
  1562. X    **/
  1563. X
  1564. X    struct passwd *password_entry, *getpwuid();
  1565. X
  1566. X    password_entry = getpwuid(getuid());
  1567. X
  1568. X    strcpy(uname, password_entry->pw_name);
  1569. X}
  1570. X
  1571. X/** some supplementary string functions for Berkeley Unix systems **/
  1572. X
  1573. Xstrspn(source, keys)
  1574. Xchar *source, *keys;
  1575. X{
  1576. X    /** This function returns the length of the substring of
  1577. X        'source' (starting at zero) that consists ENTIRELY of
  1578. X        characters from 'keys'.  This is used to skip over a
  1579. X        defined set of characters with parsing, usually. 
  1580. X    **/
  1581. X
  1582. X    register int loc = 0, key_index = 0;
  1583. X
  1584. X    while (source[loc] != '\0') {
  1585. X      key_index = 0;
  1586. X      while (keys[key_index] != source[loc])
  1587. X        if (keys[key_index++] == '\0')
  1588. X          return(loc);
  1589. X      loc++;
  1590. X    }
  1591. X
  1592. X    return(loc);
  1593. X}
  1594. X
  1595. Xstrcspn(source, keys)
  1596. Xchar *source, *keys;
  1597. X{
  1598. X    /** This function returns the length of the substring of
  1599. X        'source' (starting at zero) that consists entirely of
  1600. X        characters NOT from 'keys'.  This is used to skip to a
  1601. X        defined set of characters with parsing, usually. 
  1602. X        NOTE that this is the opposite of strspn() above
  1603. X    **/
  1604. X
  1605. X    register int loc = 0, key_index = 0;
  1606. X
  1607. X    while (source[loc] != '\0') {
  1608. X      key_index = 0;
  1609. X      while (keys[key_index] != '\0')
  1610. X        if (keys[key_index++] == source[loc])
  1611. X          return(loc);
  1612. X      loc++;
  1613. X    }
  1614. X
  1615. X    return(loc);
  1616. X}
  1617. X
  1618. Xchar *strtok(source, keys)
  1619. Xchar *source, *keys;
  1620. X{
  1621. X    /** This function returns a pointer to the next word in source
  1622. X        with the string considered broken up at the characters 
  1623. X        contained in 'keys'.  Source should be a character pointer
  1624. X        when this routine is first called, then NULL subsequently.
  1625. X        When strtok has exhausted the source string, it will 
  1626. X        return NULL as the next word. 
  1627. X
  1628. X        WARNING: This routine will DESTROY the string pointed to
  1629. X        by 'source' when first invoked.  If you want to keep the
  1630. X        string, make a copy before using this routine!!
  1631. X     **/
  1632. X
  1633. X    register int  last_ch;
  1634. X    static   char *sourceptr;
  1635. X         char *return_value;
  1636. X
  1637. X    if (source != NULL)
  1638. X      sourceptr = source;
  1639. X    
  1640. X    if (*sourceptr == '\0') 
  1641. X      return(NULL);        /* we hit end-of-string last time!? */
  1642. X
  1643. X    sourceptr += strspn(sourceptr, keys);    /* skip leading crap */
  1644. X    
  1645. X    if (*sourceptr == '\0') 
  1646. X      return(NULL);        /* we've hit end-of-string */
  1647. X
  1648. X    last_ch = strcspn(sourceptr, keys);    /* end of good stuff */
  1649. X
  1650. X    return_value = sourceptr;        /* and get the ret   */
  1651. X
  1652. X    sourceptr += last_ch;            /* ...value          */
  1653. X
  1654. X    if (*sourceptr != '\0')        /* don't forget if we're at END! */
  1655. X      sourceptr++;               /* and skipping for next time */
  1656. X
  1657. X    return_value[last_ch] = '\0';        /* ..ending right    */
  1658. X    
  1659. X    return((char *) return_value);        /* and we're outta here! */
  1660. X}
  1661. X
  1662. Xchar *strpbrk(source, keys)
  1663. Xchar *source, *keys;
  1664. X{
  1665. X    /** Returns a pointer to the first character of source that is any
  1666. X        of the specified keys, or NULL if none of the keys are present
  1667. X        in the source string. 
  1668. X    **/
  1669. X
  1670. X    register int loc = 0, key_index = 0;
  1671. X
  1672. X    while (source[loc] != '\0') {
  1673. X      key_index = 0;
  1674. X      while (keys[key_index] != '\0')
  1675. X        if (keys[key_index++] == source[loc])
  1676. X          return((char *) (source + loc));
  1677. X      loc++;
  1678. X    }
  1679. X    
  1680. X    return(NULL);
  1681. X}
  1682. X
  1683. Xchar *strchr(buffer, ch)
  1684. Xchar *buffer, ch;
  1685. X{
  1686. X    /** Returns a pointer to the first occurance of the character
  1687. X        'ch' in the specified string or NULL if it doesn't occur **/
  1688. X
  1689. X    char *address;
  1690. X
  1691. X    address = buffer;
  1692. X
  1693. X    while (*address != ch) {
  1694. X      if (*address == '\0')
  1695. X        return (NULL);
  1696. X      address++;
  1697. X    }
  1698. X
  1699. X    return ( (char *) address);
  1700. X}
  1701. X
  1702. X#endif
  1703. END_OF_src/opt_utils.c
  1704. if test 5098 -ne `wc -c <src/opt_utils.c`; then
  1705.     echo shar: \"src/opt_utils.c\" unpacked with wrong size!?
  1706. fi
  1707. # end of overwriting check
  1708. fi
  1709. echo shar: Extracting \"src/sort.c\" \(4826 characters\)
  1710. if test -f src/sort.c ; then 
  1711.   echo shar: Will not over-write existing file \"src/sort.c\"
  1712. else
  1713. sed "s/^X//" >src/sort.c <<'END_OF_src/sort.c'
  1714. X/**            sort.c                **/
  1715. X
  1716. X/** Sort mailbox header table by the field specified in the global
  1717. X    variable "sortby"...if we're sorting by something other than
  1718. X    the default SENT_DATE, also put some sort of indicator on the
  1719. X    screen.
  1720. X
  1721. X    (C) Copyright 1986, Dave Taylor
  1722. X**/
  1723. X
  1724. X#include "headers.h"
  1725. X
  1726. Xchar *sort_name();
  1727. Xvoid   qsort();
  1728. X
  1729. Xsort_mailbox(entries, visible)
  1730. Xint entries, visible;
  1731. X{
  1732. X    /** Sort the header_table definitions... If 'visible', then
  1733. X        put the status lines etc **/
  1734. X    
  1735. X    int last_index = -1;
  1736. X    int compare_headers();    /* for sorting */
  1737. X
  1738. X    dprint1(2,"\n** sorting mailbox by %s **\n\n", sort_name(FULL));
  1739. X
  1740. X    if (entries > 0)
  1741. X      last_index = header_table[current-1].index_number;
  1742. X
  1743. X    if (entries > 30 && visible)  
  1744. X      error1("sorting messages by %s", sort_name(FULL));
  1745. X    
  1746. X    qsort(header_table, (unsigned) entries, sizeof (struct header_rec), 
  1747. X          compare_headers);
  1748. X
  1749. X    if (last_index > -1)
  1750. X      find_old_current(last_index);
  1751. X
  1752. X    clear_error();
  1753. X}
  1754. X
  1755. Xint
  1756. Xcompare_headers(first, second)
  1757. Xstruct header_rec *first, *second;
  1758. X{
  1759. X    /** compare two headers according to the sortby value.
  1760. X
  1761. X        Sent Date uses a routine to compare two dates,
  1762. X        Received date is keyed on the file offsets (think about it)
  1763. X        Sender uses the truncated from line, same as "build headers",
  1764. X        and size and subject are trivially obvious!!
  1765. X     **/
  1766. X
  1767. X    char from1[SLEN], from2[SLEN];    /* sorting buffers... */
  1768. X    int  sign = 1;
  1769. X    
  1770. X    if (sortby < 0)
  1771. X      sign = -1;
  1772. X
  1773. X    switch (abs(sortby)) {
  1774. X
  1775. X      case SENT_DATE : return( sign*compare_dates(first, second));
  1776. X
  1777. X      case RECEIVED_DATE: return( sign*
  1778. X                          compare_parsed_dates(first->received, 
  1779. X                           second->received));
  1780. X
  1781. X      case SENDER    : tail_of(first->from, from1, TRUE);
  1782. X               tail_of(second->from, from2, TRUE);
  1783. X                 return( sign*strcmp(from1, from2));
  1784. X
  1785. X      case SIZE      : return( sign*(first->lines - second->lines));
  1786. X
  1787. X      case SUBJECT   : /* need some extra work 'cause of STATIC buffers */
  1788. X                       strcpy(from1, shift_lower(first->subject));    
  1789. X               return( 
  1790. X                 sign*strcmp(from1, shift_lower(second->subject)));
  1791. X
  1792. X      case STATUS    : return( sign*(first->status - second->status));
  1793. X    }
  1794. X
  1795. X    return(0);    /* never get this! */
  1796. X}
  1797. X
  1798. Xchar *sort_name(type)
  1799. Xint type;
  1800. X{
  1801. X    /** return the name of the current sort option...
  1802. X        type can be "FULL", "SHORT" or "PAD"
  1803. X    **/
  1804. X    int pad, abr;
  1805. X    
  1806. X    pad = (type == PAD);
  1807. X    abr = (type == SHORT);
  1808. X
  1809. X    if (sortby < 0) {
  1810. X      switch (- sortby) {
  1811. X        case SENT_DATE    : return( 
  1812. X                      pad?     "Reverse Date Mail Sent  " : 
  1813. X                  abr?     "Reverse-Sent" :
  1814. X                       "Reverse Date Mail Sent");
  1815. X        case RECEIVED_DATE: return(
  1816. X                  abr?     "Reverse-Received":
  1817. X                           "Reverse Date Mail Rec'vd");
  1818. X        case SENDER       : return(
  1819. X                  pad?     "Reverse Message Sender  " : 
  1820. X                  abr?     "Reverse-From":
  1821. X                       "Reverse Message Sender");
  1822. X        case SIZE         : return(
  1823. X                  abr?     "Reverse-Lines" : 
  1824. X                       "Reverse Lines in Message");
  1825. X        case SUBJECT      : return(
  1826. X                  pad?     "Reverse Message Subject " : 
  1827. X                  abr?     "Reverse-Subject" : 
  1828. X                       "Reverse Message Subject");
  1829. X        case STATUS          : return(
  1830. X                  pad?     "Reverse Message Status  " :
  1831. X                  abr?     "Reverse-Status":
  1832. X                           "Reverse Message Status");
  1833. X      }
  1834. X    }
  1835. X    else {
  1836. X      switch (sortby) {
  1837. X        case SENT_DATE    : return( 
  1838. X                        pad?   "Date Mail Sent          " : 
  1839. X                        abr?   "Sent" : 
  1840. X                       "Date Mail Sent");
  1841. X        case RECEIVED_DATE: return(
  1842. X                            pad?   "Date Mail Rec'vd        " :
  1843. X                            abr?   "Received" :
  1844. X                                   "Date Mail Rec'vd");
  1845. X        case SENDER       : return(
  1846. X                    pad?   "Message Sender          " : 
  1847. X                    abr?   "From" : 
  1848. X                       "Message Sender");
  1849. X        case SIZE         : return(
  1850. X                    pad?   "Lines in Message        " :
  1851. X                    abr?   "Lines" :
  1852. X                           "Lines in Message");
  1853. X        case SUBJECT      : return(
  1854. X                    pad?   "Message Subject         " : 
  1855. X                    abr?   "Subject" : 
  1856. X                       "Message Subject");
  1857. X        case STATUS          : return(
  1858. X                    pad?   "Message Status          " :
  1859. X                    abr?   "Status" :
  1860. X                           "Message Status");
  1861. X      }
  1862. X    }
  1863. X
  1864. X    return("*UNKNOWN-SORT-PARAMETER*");
  1865. X}
  1866. X
  1867. Xfind_old_current(index)
  1868. Xint index;
  1869. X{
  1870. X    /** Set current to the message that has "index" as it's 
  1871. X        index number.  This is to track the current message
  1872. X        when we resync... **/
  1873. X
  1874. X    register int i;
  1875. X
  1876. X    dprint1(2,"find-old-current(%d)\n", index);
  1877. X
  1878. X    for (i = 0; i < message_count; i++)
  1879. X      if (header_table[i].index_number == index) {
  1880. X        current = i+1;
  1881. X        dprint1(2,"\tset current to %d!\n", current);
  1882. X        return;
  1883. X      }
  1884. X
  1885. X    dprint1(2,"\tcouldn't find current index.  Current left as %d\n",
  1886. X        current);
  1887. X    return;        /* can't be found.  Leave it alone, then */
  1888. X}
  1889. END_OF_src/sort.c
  1890. if test 4826 -ne `wc -c <src/sort.c`; then
  1891.     echo shar: \"src/sort.c\" unpacked with wrong size!?
  1892. fi
  1893. # end of overwriting check
  1894. fi
  1895. echo shar: Extracting \"src/syscall.c\" \(5245 characters\)
  1896. if test -f src/syscall.c ; then 
  1897.   echo shar: Will not over-write existing file \"src/syscall.c\"
  1898. else
  1899. sed "s/^X//" >src/syscall.c <<'END_OF_src/syscall.c'
  1900. X/**            syscall.c        **/
  1901. X
  1902. X/** These routines are used for user-level system calls, including the
  1903. X    '!' command and the '|' commands...
  1904. X
  1905. X    (C) Copyright 1986 Dave Taylor
  1906. X**/
  1907. X
  1908. X#include "headers.h"
  1909. X
  1910. X#include <signal.h>
  1911. X
  1912. X#ifdef BSD
  1913. X#  include <sys/wait.h>
  1914. X#endif
  1915. X
  1916. Xchar *argv_zero();    
  1917. Xvoid  _exit();
  1918. X
  1919. Xint
  1920. Xsubshell()
  1921. X{
  1922. X    /** spawn a subshell with either the specified command
  1923. X        returns non-zero if screen rewrite needed
  1924. X    **/
  1925. X
  1926. X    char command[SLEN];
  1927. X    int  ret;
  1928. X
  1929. X    PutLine0(LINES-3,COLUMNS-40,"(use the shell name for a shell)");
  1930. X    PutLine0(LINES-2,0,"Shell Command: ");
  1931. X    command[0] = '\0';
  1932. X    (void) optionally_enter(command, LINES-2, 15, FALSE);
  1933. X    if (strlen(command) == 0) {
  1934. X      MoveCursor(LINES-2,0);    CleartoEOLN();
  1935. X      return(0);
  1936. X    }
  1937. X
  1938. X    MoveCursor(LINES,0);     CleartoEOLN();
  1939. X    Raw(OFF);
  1940. X    if (cursor_control)  transmit_functions(OFF);
  1941. X    
  1942. X    ret = system_call(command, USER_SHELL);
  1943. X
  1944. X    PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
  1945. X
  1946. X    Raw(ON);
  1947. X    (void) getchar();
  1948. X    if (cursor_control)  transmit_functions(ON);
  1949. X
  1950. X    if (ret != 0) error1("Return code was %d", ret);
  1951. X    return(1);
  1952. X}
  1953. X
  1954. Xsystem_call(string, shell_type)
  1955. Xchar *string;
  1956. Xint   shell_type;
  1957. X{
  1958. X    /** execute 'string', setting uid to userid... **/
  1959. X    /** if shell-type is "SH" /bin/sh is used regardless of the 
  1960. X        users shell setting.  Otherwise, "USER_SHELL" is sent **/
  1961. X
  1962. X    int stat = 0, pid, w;
  1963. X#ifdef BSD
  1964. X    union wait status;
  1965. X#else
  1966. X    int status;
  1967. X#endif
  1968. X    register int (*istat)(), (*qstat)();
  1969. X    
  1970. X    dprint2(2,"System Call: %s\n\t%s\n", shell_type == SH? "/bin/sh" : shell,
  1971. X        string);
  1972. X
  1973. X#ifdef NO_VM        /* machine without virtual memory! */
  1974. X    if ((pid = fork()) == 0) {
  1975. X#else
  1976. X    if ((pid = vfork()) == 0) {
  1977. X#endif
  1978. X      setgid(groupid);    /* and group id            */
  1979. X      setuid(userid);    /* back to the normal user! */
  1980. X
  1981. X      if (strlen(shell) > 0 && shell_type == USER_SHELL) {
  1982. X        execl(shell, argv_zero(shell), "-c", string, (char *) 0);
  1983. X      }
  1984. X      else 
  1985. X        execl("/bin/sh", "sh", "-c", string, (char *) 0);
  1986. X      _exit(127);
  1987. X    }
  1988. X
  1989. X    istat = signal(SIGINT, SIG_IGN);
  1990. X    qstat = signal(SIGQUIT, SIG_IGN);
  1991. X
  1992. X    while ((w = wait(&status)) != pid && w != -1)
  1993. X        ;
  1994. X
  1995. X#ifdef BSD
  1996. X    if (status.w_retcode != 0) stat = status.w_retcode;
  1997. X#else
  1998. X    if (w == -1) stat = status;
  1999. X#endif
  2000. X    
  2001. X    signal(SIGINT, istat);
  2002. X    signal(SIGQUIT, qstat);
  2003. X
  2004. X    return(stat);
  2005. X}
  2006. X
  2007. Xint
  2008. Xdo_pipe()
  2009. X{
  2010. X    /** pipe the tagged messages to the specified sequence.. **/
  2011. X
  2012. X    char command[SLEN], buffer[LONG_SLEN], message_list[SLEN];
  2013. X    register int  ret, tagged = 0, i;
  2014. X
  2015. X    message_list[0] = '\0';    /* NULL string to start... */
  2016. X
  2017. X    for (i=0; i < message_count; i++)
  2018. X      if (ison(header_table[i].status, TAGGED)) {
  2019. X        sprintf(message_list,"%s %d", message_list, 
  2020. X            header_table[i].index_number);
  2021. X        tagged++;
  2022. X      }
  2023. X
  2024. X    if (tagged > 1)
  2025. X      PutLine0(LINES-2,0,"Pipe tagged msgs to: ");
  2026. X    else if (tagged) 
  2027. X      PutLine0(LINES-2,0,"Pipe tagged msg to : ");
  2028. X    else {
  2029. X      PutLine0(LINES-2,0,"Pipe current msg to: ");
  2030. X      sprintf(message_list,"%d", header_table[current-1].index_number);
  2031. X    }
  2032. X
  2033. X    command[0] = '\0';
  2034. X
  2035. X    (void) optionally_enter(command, LINES-2, 21, FALSE);
  2036. X    if (strlen(command) == 0) {
  2037. X      MoveCursor(LINES-2,0);    CleartoEOLN();
  2038. X      return(0);
  2039. X    }
  2040. X
  2041. X    MoveCursor(LINES,0);     CleartoEOLN();
  2042. X    Raw(OFF);
  2043. X
  2044. X    if (cursor_control)  transmit_functions(OFF);
  2045. X    
  2046. X    sprintf(buffer, "%s -f %s -h %s | %s",
  2047. X        readmsg,
  2048. X        infile,
  2049. X        message_list,
  2050. X        command);
  2051. X    
  2052. X    ret = system_call(buffer, USER_SHELL);
  2053. X
  2054. X    PutLine0(LINES, 0, "\n\nPress <return> to return to ELM: ");
  2055. X    Raw(ON);
  2056. X    (void) getchar();
  2057. X    if (cursor_control)  transmit_functions(ON);
  2058. X
  2059. X    if (ret != 0) error1("Return code was %d", ret);
  2060. X    return(1);
  2061. X}
  2062. X
  2063. Xprintmsg()
  2064. X{
  2065. X    /** Print current message or tagged messages using 'printout' 
  2066. X        variable.  Error message iff printout not defined! **/
  2067. X
  2068. X    char buffer[LONG_SLEN], filename[SLEN], printbuffer[LONG_SLEN];
  2069. X    char message_list[SLEN];
  2070. X    register int  retcode, tagged = 0, i;
  2071. X
  2072. X    if (strlen(printout) == 0) {
  2073. X      error("Don't know how to print - option \"printmail\" undefined!");
  2074. X      return;
  2075. X    }
  2076. X    
  2077. X    message_list[0] = '\0';    /* reset to null... */
  2078. X
  2079. X    for (i=0; i < message_count; i++) 
  2080. X      if (header_table[i].status & TAGGED) {
  2081. X        sprintf(message_list, "%s %d", message_list, 
  2082. X            header_table[i].index_number);
  2083. X        tagged++;
  2084. X      }
  2085. X
  2086. X    if (! tagged)
  2087. X      sprintf(message_list," %d", header_table[current-1].index_number);
  2088. X
  2089. X    sprintf(filename,"%s%d", temp_print, getpid());
  2090. X
  2091. X    if (in_string(printout, "%s"))
  2092. X      sprintf(printbuffer, printout, filename);
  2093. X    else
  2094. X      sprintf(printbuffer, "%s %s", printout, filename);
  2095. X
  2096. X    sprintf(buffer,"(%s -p -f %s%s > %s; %s 2>&1) > /dev/null",
  2097. X        readmsg, infile, message_list, 
  2098. X        filename,
  2099. X        printbuffer);
  2100. X    
  2101. X    dprint0(2,"Printing system call...\n");
  2102. X
  2103. X      Centerline(LINES, "queueing...");
  2104. X
  2105. X    if ((retcode = system_call(buffer, SH)) == 0) {
  2106. X      sprintf(buffer, "Message%s queued up to print", plural(tagged));
  2107. X      Centerline(LINES, buffer);
  2108. X    }
  2109. X    else
  2110. X      error1("Printout failed with return code %d", retcode);
  2111. X
  2112. X    unlink(filename);    /* remove da temp file! */
  2113. X}
  2114. X
  2115. Xlist_folders()
  2116. X{
  2117. X    /** list the folders in the users FOLDERHOME directory.  This is
  2118. X        simply a call to "ls -C"
  2119. X    **/
  2120. X
  2121. X    char buffer[SLEN];
  2122. X
  2123. X    CleartoEOS();    /* don't leave any junk on the bottom of the screen */
  2124. X    sprintf(buffer, "cd %s;ls -C", folders);
  2125. X    printf("\n\rContents of your folder directory:\n\r\n\r");
  2126. X    system_call(buffer, SH); 
  2127. X    printf("\n\r");
  2128. X}
  2129. X
  2130. END_OF_src/syscall.c
  2131. if test 5245 -ne `wc -c <src/syscall.c`; then
  2132.     echo shar: \"src/syscall.c\" unpacked with wrong size!?
  2133. fi
  2134. # end of overwriting check
  2135. fi
  2136. echo shar: End of archive 4 \(of 19\).
  2137. cp /dev/null ark4isdone
  2138. DONE=true
  2139. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; do
  2140.     if test ! -f ark${I}isdone ; then
  2141.     echo shar: You still need to run archive ${I}.
  2142.     DONE=false
  2143.     fi
  2144. done
  2145. if test "$DONE" = "true" ; then
  2146.     echo You have unpacked all 19 archives.
  2147.     echo "See the Instructions file"
  2148.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2149. fi
  2150. ##  End of shell archive.
  2151. exit 0
  2152.